package com.oig.sys.oauth.config;

import com.oig.sys.oauth.handler.SsoLogoutSuccessHandler;
import com.oig.sys.oauth.provider.CustomizeDaoAuthenticationProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;


@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig  {

    private final UserDetailsService authUserDetailsService;

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        CustomizeDaoAuthenticationProvider authenticationProvider = new CustomizeDaoAuthenticationProvider();
        authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        authenticationProvider.setUserDetailsService(authUserDetailsService);
        return authenticationProvider;
    }

    @Bean
    public LogoutSuccessHandler logoutSuccessHandler(){
        return new SsoLogoutSuccessHandler();
    }


    /**
     * HttpSecurity就是一个构建类，它的使命就是构建出一个SecurityFilterChain
     * 当一个请求HttpServletRequest进入SecurityFilterChain时，会通过matches方法来确定是否满足条件进入过滤器链
     *
     *
     * Spring security 自带的 部分过滤器，每一道过滤器都有一个对应的配置器(configurer)，http 后面每一个 and 就对应一个配置器的配置
     * cors -> CsrfConfigurer -> CorsFilter
     * csrf -> CsrfConfigurer -> CsrfFilter
     * WebAsyncManagerIntegrationFilter   用于集成SecurityContext到Spring异步执行机制中的WebAsyncManager。用来处理异步请求的安全上下文
     * exceptionHandling -> ExceptionHandlingConfigurer -> ExceptionTranslationFilter
     * headers -> HeadersConfigurer -> HeaderWriterFilter
     * sessionManagement -> SessionManagementConfigurer -> SessionManagementFilter
     * securityContext -> SecurityContextConfigurer -> SecurityContextPersistenceFilter
     * requestCache -> RequestCacheConfigurer -> RequestCacheFilter
     * anonymous -> AnonymousConfigurer -> AnonymousAuthenticationFilter
     * servletApi -> ServletApiConfigurer -> SecurityContextHolderAwareRequestFilter
     * DefaultLoginPageConfigurer -> DefaultLoginPageGeneratingFilter           生成默认的登录页。默认 /login 。
     * logout -> LogoutConfigurer -> LogoutFilter                               生成默认的退出页。 默认 /logout 。
     *
     * AuthorizeHttpRequestsConfigurer
     */
    @Bean
    @Order(1)
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> authorize
                .antMatchers("/sso/**","/images/**","/css/**","/js/**","/v3/api-docs/**","/actuator/**","/error").permitAll()
                .antMatchers(HttpMethod.OPTIONS,"/oauth2/token").permitAll()//跨域请求会先进行一次options请求
                .anyRequest().authenticated()).csrf().disable()
                //用了网关聚合  要允许跨域，corsFilter在swagger 里面已经配置了，这边不需要再配置
                .cors().and()
                .headers().frameOptions().sameOrigin();// 避免iframe同源无法登录
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
//        http.formLogin(loginCfg->loginCfg.loginPage("/sso/loginPage").loginProcessingUrl("/login").failureForwardUrl("/sso/loginPage"))
//                .logout(logoutCfg->logoutCfg.logoutSuccessHandler(logoutSuccessHandler()));
        http.formLogin(Customizer.withDefaults())
                .authenticationProvider(authenticationProvider())
                .logout(logoutCfg->logoutCfg.logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID"));
        return http.build();
    }




}
